#ifndef _LOGGER_H_
#define _LOGGER_H_
//=============================================================================
/**
 *  @file    RegMutex.h
 *
 *  ver 1.0.0 Reg Exp, for Reg Develop
 *
 *  @author Reg  2011/01/13 created.
 */
//=============================================================================
#include <memory>
#include <pthread.h>
#include <string>
#include <time.h>
/// mutex class.
/// This is a mutual exclusion object for synchronizing access to shared
/// memory areas for several threads.

class RegMutex {
    public:
    RegMutex()
    {
        pthread_mutex_init(&mHandle, NULL);
    }

    ~RegMutex()
    {
        pthread_mutex_destroy(&mHandle);
    }

    inline void lock()
    {
        pthread_mutex_lock(&mHandle);
    }
    inline bool try_lock()
    {
        return (pthread_mutex_trylock(&mHandle) == 0) ? true : false;
    }
    inline void unlock()
    {
        pthread_mutex_unlock(&mHandle);
    }

    private:
    pthread_mutex_t mHandle;
};

//=============================================================================
/**
 *  @file    SignleTon.h
 *
 *  ver 1.0.0 Reg Exp, for Reg Develop  Logger Framework.
 *
 *  @author Reg  2011/01/12 created.
 */
//=============================================================================
using namespace std;
//================SingleTon Template Definition=================
/**
 *The Singleton C++ Design Pattern is a C++ design
 *that creates one single instance of a class
 *that can be used throughout multiple files and large projects.
 *
 *Think of C++ Singleton like a global class
 *that can be accessed at any moment and
 *will be created only once, if it hasn't already been initialized.
 *
 *Reg created . 2011/01/12
 */

template <class T> class Singleton {
    public:
    /**
     *Create one single instance of the template
     */
    static inline T *instance();

    protected:
    /**
     *Default constructor ,create one instance
     */
    Singleton(void)
    {
    }

    /**
     *Destructor
     */
    ~Singleton(void)
    {
    }

    /**
     *Copy contructor
     *Using an existing object value to initialize a new objects
     */
    Singleton(const Singleton &)
    {
    }

    /**
     *Overloaded assignment
     */
    Singleton &operator=(const Singleton &)
    {
    }

    /**
     *Smart pointer
     *Release resource automaticly
     *when the _instance leaves scope
     */
    static auto_ptr<T> _instance;

    static RegMutex _mRegmux;
};

template <class T> auto_ptr<T> Singleton<T>::_instance;

template <class T> RegMutex Singleton<T>::_mRegmux;

/**
 *Create new instance
 *The method is not thread-safe
 */
template <class T> inline T *Singleton<T>::instance()
{
    if (0 == _instance.get()) {
        _mRegmux.lock();
        if (0 == _instance.get()) {
            _instance.reset(new (nothrow) T);
        }
        _mRegmux.unlock();
    }
    return _instance.get();
}

// Class that will implement the singleton mode,
// must use the macro in it's delare file
#define DECLARE_SINGLETON_CLASS(type)                                                    \
    friend class auto_ptr<type>;                                                         \
    friend class Singleton<type>;

//=============================================================================
/**
 *  @file    LogLevel.h
 *
 *  ver 1.0.0 Reg Exp, for Reg Develop  Logger Framework.
 *
 *  @author Reg  2011/01/12 created.
 */
//=============================================================================

//================Macro LogLevel define=================

// log level switch type
// EMERG_LOG_LEVEL 0000 0001
// ALERT_LOG_LEVEL 0000 0010
// CRIT_LOG_LEVEL  0000 0100
// ERROR_LOG_LEVEL 0000 1000
// WARN_LOG_LEVEL  0001 0000
// NOTICE_LOG_LEVEL 0010 0000
// INFO_LOG_LEVEL  0100 0000
// FATAL_LOG_LEVEL 1000 0000
// ALL_LOG_LEVEL   1111 1111
typedef unsigned char UCHAR;

typedef int LogLevel;

/**
 * var const LogLevel OFF_LOG_LEVEL
 * The OFF_LOG_LEVEL is used during configuration to
 * turn off logging.
 */
const LogLevel OFF_LOG_LEVEL = 9;

const LogLevel ON_LOG_LEVEL = 10;

/**
 * var const LogLevel FATAL_LOG_LEVEL
 * The FATAL_LOG_LEVEL designates very serious error
 * events that will presumably lead the application to abort.
 */
const LogLevel FATAL_LOG_LEVEL = 8;

/**
 * var const LogLevel EMERG_LOG_LEVEL
 * The LogLevel designates system is unusable.
 */
const LogLevel LOG_EMERG = 0;

/**
 * var const LogLevel ALERT_LOG_LEVEL
 * The LogLevel designates action must be token
 * immediately.
 */
const LogLevel LOG_ALERT = 1;

/**
 * var const LogLevel CRIT_LOG_LEVEL
 * The LogLevel designates  critical conditions.
 */
const LogLevel LOG_CRIT = 2;

/**
 * var const LogLevel ERROR_LOG_LEVEL
 * The LogLevel designates error events that
 * might still allow the application to continue running.
 */
const LogLevel LOG_ERR = 3;

/**
 * var const LogLevel WARN_LOG_LEVEL
 * The LogLevel designates potentially harmful
 * situations.
 */
const LogLevel LOG_WARNING = 4;

/**
 * var const LogLevel NOTICE_LOG_LEVEL
 * The LogLevel designates normal but significant
 * condition.
 */
const LogLevel LOG_NOTICE = 5;

/**
 * var const LogLevel INFO_LOG_LEVEL
 * The LogLevel designates informational
 * messages  that highlight the progress of the application at
 * coarse-grained  level.
 */
const LogLevel LOG_INFO = 6;

/**
 * var const LogLevel DEBUG_LOG_LEVEL
 * The LogLevel designates fine-grained
 * informational events that are most useful to debug an application.
 */
const LogLevel LOG_DEBUGG = 7;

/**
 * var const LogLevel TRACE_LOG_LEVEL
 * The LogLevel is used to "trace" entry
 * and exiting of methods.
 */
const LogLevel TRACE_LOG_LEVEL = 11;

/**
 * var const LogLevel ALL_LOG_LEVEL
 * The LogLevel is used during configuration to
 * turn on all logging.
 */
const LogLevel ALL_LOG_LEVEL = TRACE_LOG_LEVEL;

/**
 * var const LogLevel NOT_SET_LOG_LEVEL
 * The LogLevel is used to indicated that
 * no particular LogLevel is desired and that the default should be used.
 */
const LogLevel NOT_SET_LOG_LEVEL = -1;

/**
 * This method type defined the signature of methods that convert LogLevels
 * into strings.
 * <p>
 * <b>Note:</b> Must return an empty <code>tstring</code> for unrecognized values.
 */
// typedef const char * (*LogLevelToStringMethod)(LogLevel ll);

/**
 * This method type defined the signature of methods that convert strings
 * into LogLevels.
 * <p>
 * <b>Note:</b> Must return <code>NOT_SET_LOG_LEVEL</code> for unrecognized values.
 */
// typedef LogLevel (*StringToLogLevelMethod)(const String &arg);

//=============================================================================
/**
 *  @file    Logger.h
 *
 *  ver 1.0.0 Reg Exp, for Reg Develop  Logger Framework.
 *
 *  @author Reg  2011/01/12 created.
 */
//=============================================================================

// log manager class
// thread-safe
class Logger {
    public:
    // Constructor
    Logger();

    // Destructor
    ~Logger();

    private:
    // synchronous handle
    RegMutex mregMux;

    // The log level switch
    UCHAR mLogSwitch;

    // store module name
    char mModuleName[512];

    // store path
    char mStorePath[512];

    // file handle //whb-2014.04.04
    int mFileHandle;
    // current log file name; //whb-2014.04.04
    std::string mFileName;
    // if splited by file size //whb-2015.11.20
    long mLogBySize;
    int mFileSeq;    // file sequence  whb-2015.11.20
    bool mSplitTime; //是否按小时切分
    public:
    // Disable the LogLevel of this Logger.
    void disableLogLevel(LogLevel ll);

    // Enable the LogLevel of this Logger.
    void enableLogLevel(LogLevel ll);

    // Set module name
    void setModuleName(const char *modulename);

    // Set store path
    void setStorePath(const char *storepath);

    // set sotre logfile by size
    void setLogFileBySize(long fileMaxSize);

    void setLogSplitByHout(bool bSplit);

    // Output msg into logfile
    void writelog(const char *fileName, int line, const char *function, LogLevel ll, int errnum, const char *format, ...);

    private:
    void closeFile();
    bool openFile(const char *file);
    void getLogFileName(std::string &logFileName);
};
typedef Singleton<Logger> LOGGER;

#define WRITE_LOG(fmt, ...)                                                              \
    LOGGER::instance()->writelog(__FILE__, __LINE__, __FUNCTION__, fmt, __VA_ARGS__)

#endif
